﻿package nl.haemers.utils 
{
	import flash.events.Event;
	import flash.events.ErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.HTTPStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.IOErrorEvent;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.net.sendToURL;
	import flash.utils.Timer;
	
	import nl.haemers.events.ServerEvent;
	/**
	 * ...
	 * @author Jonathan Haemers
	 */
	public class ServerRequest extends EventDispatcher
	{
		public static const POST		:String = "post";
		public static const GET			:String = "get";
		
		private var _timeout			:Number = 6000;
		
		private var _timer				:Timer;
		
		private var urlLoader			:URLLoader;
		private var _urlRequest			:URLRequest;
		
		private var _result				:*;
		
		public function ServerRequest( url:String = "") 
		{
			_urlRequest = new URLRequest( url );
			urlLoader = new URLLoader();
			
			createTimer();
			configListeners();
		}
		
		/** Public methods **/
		/**
		 * Send data to the server and wait for data
		 */
		public function sendAndLoad() : void
		{
			urlLoader.load( _urlRequest );
		}
		/**
		 * Send data to server without waiting for response
		 */
		public function send() : void
		{
			sendToURL( _urlRequest );
		}
		
		/**
		 * Destroy function for clearing memory, closing the load and removing the EventListeners
		**/ 
		public function destroy() : void
		{
			cancelRequest();
			clearTimer();
			removeEventListeners();
		}
		
		/** Getters & Setters **/
		/**
		 * The request method: POST or GET
		 */
		public function get method() : String
		{
			return _urlRequest.method;
		}
		public function set method( value:String ) : void
		{
			_urlRequest.method = value;
		}
		
		/**
		 * The url to be requested
		 */
		public function get url() : String
		{
			return (_urlRequest != null) ? _urlRequest.url : "";
		}
		public function set url( value:String ) : void
		{
			_urlRequest.url = value;
		}
		/**
		 * The urlRequest
		 */
		public function get urlRequest() : URLRequest
		{
			return _urlRequest;
		}
		public function set urlRequest( value:URLRequest ) : void
		{
			_urlRequest = value;
		}
		
		/**
		 * Data to send with the request
		 */
		public function get urlVars() : URLVariables
		{
			return _urlRequest.data as URLVariables;
		}
		public function set urlVars( value:URLVariables ) : void
		{
			_urlRequest.data = value;
		}
		
		/**
		 * Set timeout in ms
		 * @default 60seconds
		 */
		public function set timeout( value:Number ) : void
		{
			_timeout = value;
		}
		
		/**
		 * @return result : *
		 */
		public function get result() : *
		{
			return _result;
		}
		/** Protected methods **/
		
		/** Private methods **/
		/**
		 * @private
		 */
		private function configListeners() : void
		{
			urlLoader.addEventListener(Event.OPEN, openHandler);
			urlLoader.addEventListener(Event.COMPLETE, completeHandler);
			urlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
			urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		}
		/**
		 * @private
		 */
		private function openHandler( e:Event ) : void
		{
			configTimer();
			_timer.start();
			if (hasEventListener(Event.OPEN))
			{
				dispatchEvent(e);
			}
		}
		/**
		 * @private
		 */
		private function completeHandler(e:Event):void 
		{
			_timer.stop();
			_timer.reset();
			
			_result = e.target.data;
            dispatchEvent(e);
        }
		/**
		 * @private
		 */
        private function progressHandler(e:ProgressEvent) : void 
		{
            trace("progressHandler loaded:" + e.bytesLoaded + " total: " + e.bytesTotal);
			if (hasEventListener(ProgressEvent.PROGRESS))
			{
				dispatchEvent(e);
			}
        }
		/**
		 * @private
		 */
        private function securityErrorHandler(e:SecurityErrorEvent) : void 
		{
            trace("securityErrorHandler: " + e);
			if (hasEventListener(SecurityErrorEvent.SECURITY_ERROR))
			{
				dispatchEvent(e);
			}
			else if (hasEventListener(ErrorEvent.ERROR))
			{
				dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, "Er is iets mis gegaan. Probeer het later nog een keer!"));
			}
        }
		/**
		 * @private
		 */
        private function httpStatusHandler(e:HTTPStatusEvent) : void 
		{
            trace("httpStatusHandler: " + e);
			if (hasEventListener(HTTPStatusEvent.HTTP_STATUS))
			{
				dispatchEvent(e);
			}
        }
		/**
		 * @private
		 */
        private function ioErrorHandler(e:IOErrorEvent) : void 
		{
            trace("ioErrorHandler: " + e);
			if (hasEventListener(IOErrorEvent.IO_ERROR))
			{
				dispatchEvent(e);
			}
			else if (hasEventListener(ErrorEvent.ERROR))
			{
				dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, "De verbinding met de server is verbroken. Probeer het later nog een keer!"));
			}
        }
		/**
		 * @private
		 */
		private function createTimer() : void
		{
			_timer = new Timer(0);
			_timer.addEventListener(TimerEvent.TIMER, timeoutHandler);
		}
		/**
		 * @private
		 */
		private function configTimer() : void
		{
			_timer.delay = _timeout;
		}
		/**
		 * @private
		 */
		private function timeoutHandler( e:TimerEvent ) : void
		{
			cancelRequest();
			
			dispatchEvent(new ServerEvent(ServerEvent.TIME_OUT));
		}
		/**
		 * @private
		 */
		private function cancelRequest() : void
		{
			urlLoader.close();
			_timer.stop();
			_timer.reset();
		}
		/**
		 * @private
		 */
		private function clearTimer() : void
		{
			_timer.removeEventListener(TimerEvent.TIMER, timeoutHandler);
		}
		/**
		 * @private
		 */
		private function removeEventListeners() : void
		{
			urlLoader.removeEventListener(Event.COMPLETE, completeHandler);
			urlLoader.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
			urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			urlLoader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		}
	}
}